package com.rj.bd.common.utils;
/**
 * @desc   七牛云分布式文件上传工具类
 * @author hbrj
 */
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.Map;
import java.util.UUID;

import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.storage.persistent.FileRecorder;
import com.qiniu.util.Auth;


public class QiNiuUploadUtils {
	//1.七牛云账号的accessKey
	private static	String accessKey ;
	//2.七牛云账号的secretKey
	private static	String secretKey ;
	//3.七牛云账号的bucket
	private static	String bucket ;

	//4.指定上传文件的key(默认不指定key的情况下，以文件内容的hash值作为文件名)
	private static	String key;

	//5.绑定的bucket的域名
	private static  String  domainOfBucket;//用户 bucket 绑定的下载域名


	/**1.通过PropertuUtils工具类加载七牛云的属性配置文件之QiNiu.properties**/
	static{
		try
		{
			Map<String, Object> map = PropertuUtils.getInfoFromProperties("QiNiu.properties");
			//map.forEach((k, v)->System.out.println(k+":"+v));
			accessKey=(String) map.get("accessKey");
			secretKey=(String) map.get("secretKey");
			bucket=(String) map.get("bucket_public");
			domainOfBucket=(String) map.get("domainOfBucket");
		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * @desc 2.构造一个带指定 Region 对象的配置类		
	 * @return
	 */
	public   Configuration getCfg() {
		//1.构造一个带指定 Region 对象的配置类
		Configuration cfg = new Configuration(Region.huabei());//因为我在创建工作空间的时候，选择的是华北，那么此时就要调用huabei()
		cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
		return cfg;
	}

	/**
	 * @desc  3.获取上传的token值
	 * @return
	 */
	public   String getUploadToken() {
		Auth auth = Auth.create(accessKey, secretKey);
		String upToken = auth.uploadToken(bucket, key);
		return upToken;
	}

	/**
	 * @desc  4.解析上传成功的结果
	 * @param response
	 * @throws QiniuException
	 */
	public void defaultPutRetInfo(Response response) throws QiniuException {
		//4.解析上传成功的结果

		DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
		System.out.println(putRet.key);
		System.out.println(putRet.hash);
	}


	/**
	 * @desc  5.字节数组上传(常用在图片上传的时候)
	 * @param uploadBytes:上传的字节数组
	 * @param fileName：文件名字
	 */
	public  String  uploadFiles(byte[] uploadBytes, String fileName)  {
		//1.获取上传凭证
		String upToken = this.getUploadToken();
		//2.利用UploadManager上传管理器类进行上传操作
		UploadManager uploadManager = new UploadManager(getCfg());
		//3指定上传至Oss服务器文件名称，使用\分隔还能指定目录
		String resultFileName= UUID.randomUUID().toString()+"-"+fileName;
		String key = "images/"+resultFileName;
		try
		{
			//4调用uploadManager类中的put()方法进行上传
			Response response = uploadManager.put(uploadBytes, key, upToken);
			//5.解析上传成功的结果(打印在控制台)
			defaultPutRetInfo(response);
			//6.获取上传成功之后的fileUrl
			String fileUrl = getFileUrl(key, response);
			if (fileUrl != null) { return fileUrl;}
		}
		catch (QiniuException ex)
		{
			//7.上传失败的异常处理
			uploadFailure(ex);
		}
		return "上传失败" ;
	}


	/**
	 * @desc  6.数据流上传(电子文档或者不太大的文件建议使用)
	 * @param inputStream：文件的数据流
	 * @param fileName：文件的名字
	 */
	public String uploadFiles(InputStream inputStream,String fileName)
	{
		//1.获取上传凭证
		String upToken = this.getUploadToken();
		//2.利用UploadManager上传管理器类进行上传操作
		UploadManager uploadManager = new UploadManager(getCfg());
		//3指定上传至Oss服务器文件名称，使用\分隔还能指定目录
		String resultFileName= UUID.randomUUID().toString()+"-"+fileName;
		String key = "files/" + resultFileName;
		try
		{
			//4.这里演示的是InputStream对象的上传，适用于所有的InputStream子类。这里的ByteInputStream只用于演示目的，实际用法根据情况而定。
			Response response = uploadManager.put(inputStream,key,upToken,null, null);
			//5.解析上传成功的结果(打印在控制台)
			defaultPutRetInfo(response);
			//6.获取上传成功之后的fileUrl
			String fileUrl = getFileUrl(key, response);
			if (fileUrl != null) { return fileUrl;}
		}
		catch (QiniuException ex)
		{
			//7.上传失败的异常处理
			uploadFailure(ex);
		}
		return "上传失败" ;
	}

	/**
	 * @desc  7.断点续传（针对超大文件使用）
	 * @param localFilePath：上传的文件的位置
	 * @param fileName：文件的名字
	 */
	public String uploadFiles(String localFilePath,String fileName)
	{
		try
		{
			//1.获取上传凭证
			String upToken = this.getUploadToken();
			//2.调用getCfg()方法获取cfg对象，并设置为并行处理
			Configuration cfg = this.getCfg();
			cfg.resumableUploadMaxConcurrentTaskCount = 2;
			//3.上传过程中临时文件的路径
			String localTempDir = Paths.get(System.getProperty("java.io.tmpdir"), bucket).toString();
			System.out.println("localTempDir-->"+localTempDir);
			//4.设置断点续传文件进度保存目录
			FileRecorder fileRecorder = new FileRecorder(localTempDir);
			//5.利用UploadManager上传管理器类进行上传操作
			UploadManager uploadManager = new UploadManager(cfg, fileRecorder);
			//6指定上传至Oss服务器文件名称，使用\分隔还能指定目录
			String resultFileName= UUID.randomUUID().toString()+"-"+fileName;
			String key = "largeFiles/"+resultFileName;
			Response response = uploadManager.put(localFilePath, key, upToken);
			//7.解析上传成功的结果
			defaultPutRetInfo(response);
			//8.获取上传成功之后的fileUrl
			String fileUrl = getFileUrl(key, response);
			if (fileUrl != null) { return fileUrl;}
		}
		catch (QiniuException ex)
		{
			//9.上传失败的异常处理
			uploadFailure(ex);
		}
		catch (IOException e)
		{   //10.断点续传文件进度保存异常处理
			throw new RuntimeException("断点续传文件进度保存异常");
		}
		return "上传失败" ;
	}

	/**
	 * @desc  8.获取上传成功之后的fileUrl
	 * @param response：上传成功之后的response对象
	 * @return
	 */
	private String getFileUrl(String key, Response response)  {
		// 解析上传结果
		if (response.isOK())
		{
			// 获取上传后的文件 URL
			String fileUrl = domainOfBucket + "/" +key;
			System.out.println( "上传成功！文件 URL: " + fileUrl);
			return fileUrl;
		}
		return null;
	}

	/**
	 * @desc 9.上传失败的异常处理
	 * @param ex :异常对象
	 */
	private void uploadFailure(QiniuException ex) {
		if (ex.response != null)
		{
			System.err.println(ex.response);
			String body = ex.response.toString();
			System.err.println(body);
		}
		throw new RuntimeException(ex);
	}
}
